﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using TeamCityMonitor.Models;
using TeamCityMonitor.Repository;
using TeamCityMonitor.Repository.Caches;
using TeamCitySharp.DomainEntities;

namespace TeamCityMonitor.Controllers
{
    public class StatisticsController : Controller
    {
        private TeamCityRepository repository;
        private List<User> users;
        private List<BuildConfig> configurations;

        public StatisticsController()
        {
            repository = new TeamCityRepository(new UserPictureRepository());
            users = repository.GetUsers().ToList();
            configurations = repository.GetBuildConfigurations().ToList();
        }

        public ActionResult Index()
        {
            ViewBag.NoOfProjects = repository.GetNoOfProjects();
            ViewBag.NoOfConfigurations = repository.GetNoOfConfigurations();
            ViewBag.NoOfUsers = repository.GetUsers().Count();

            ViewBag.NoOfBuilds = repository.GetNoOfBuilds();
            ViewBag.NoOfFailingBuilds = repository.GetNoOfFailingBuilds();
            ViewBag.NoOfErrorBuilds = repository.GetNoOfErrorBuilds();
            ViewBag.NoOfSuccessfullBuilds = repository.GetNoOfSuccessfullBuilds();
            ViewBag.NoOfUnknownBuilds = repository.GetNoOfUnknownBuilds();

            ViewBag.NoOfBuildsSince = repository.GetNoOfBuildsSince();
            ViewBag.NoOfFailingBuildsSince = repository.GetNoOfFailingBuildsSince();
            ViewBag.NoOfErrorBuildsSince = repository.GetNoOfErrorBuildsSince();
            ViewBag.NoOfSuccessfullBuildsSince = repository.GetNoOfSuccessfullBuildsSince();
            ViewBag.NoOfUnknownBuildsSince = repository.GetNoOfUnknownBuildsSince();
            ViewBag.NoOfDaysBack = Properties.Settings.Default.DaysBackToPerformStatistisc;

            return View();
        }

        public ActionResult Users()
        {
            return View();
        }

        public ActionResult GetUserStatistics()
        {
            var models = new List<UserStatistics>();

            var totalBuilds = repository.GetNoOfBuilds();
            var totalErrorBuilds = repository.GetNoOfErrorBuilds();
            var totalFailureBuilds = repository.GetNoOfFailingBuilds();
            var totalSuccessfullBuilds = repository.GetNoOfSuccessfullBuilds();
            var totalUnknownBuilds = totalBuilds - totalErrorBuilds - totalFailureBuilds - totalSuccessfullBuilds;

            users.ForEach(user =>
                              {
                                  var stats = new UserStatistics
                                                  {
                                                      Username = user.Username,
                                                      DisplayName = user.Name,
                                                      BuildCount = repository.GetNoOfBuildsByUser(user),
                                                      ErrorBuildCount = repository.GetNoOfErrorBuildsByUser(user),
                                                      FailureBuildCount = repository.GetNoOfFailingBuildsByUser(user),
                                                      SuccessfullBuildCount = repository.GetNoOfSuccessfullBuildsByUser(user),
                                                  };
                                  stats.UnknownBuildCount = stats.BuildCount - stats.ErrorBuildCount - stats.FailureBuildCount - stats.SuccessfullBuildCount;
                                  stats.UnknownBuildPercentage = GetPercentageAsString(stats.UnknownBuildCount, totalUnknownBuilds);

                                  stats.BuildPercentage = GetPercentageAsString(stats.BuildCount, totalBuilds);
                                  stats.ErrorBuildPercentage = GetPercentageAsString(stats.ErrorBuildCount, totalErrorBuilds);
                                  stats.FailureBuildPercentage = GetPercentageAsString(stats.FailureBuildCount, totalFailureBuilds);
                                  stats.SuccessfullBuildPercentage = GetPercentageAsString(stats.SuccessfullBuildCount, totalSuccessfullBuilds);

                                  models.Add(stats);
                              }
                );

            return PartialView("UserStatistics", models);
        }

        public ActionResult GetUserIndividualStatistics()
        {
            var models = new List<UserStatistics>();

            users.ForEach(user =>
            {
                var stats = new UserStatistics
                {
                    Username = user.Username,
                    DisplayName = user.Name,
                    BuildCount = repository.GetNoOfBuildsByUser(user),
                    ErrorBuildCount = repository.GetNoOfErrorBuildsByUser(user),
                    FailureBuildCount = repository.GetNoOfFailingBuildsByUser(user),
                    SuccessfullBuildCount = repository.GetNoOfSuccessfullBuildsByUser(user),
                };

                stats.UnknownBuildCount = stats.BuildCount - stats.ErrorBuildCount - stats.FailureBuildCount - stats.SuccessfullBuildCount;
                stats.UnknownBuildPercentage = GetPercentageAsString(stats.UnknownBuildCount, stats.BuildCount);

                stats.BuildPercentage = GetPercentageAsString(stats.BuildCount, stats.BuildCount);
                stats.ErrorBuildPercentage = GetPercentageAsString(stats.ErrorBuildCount, stats.BuildCount);
                stats.FailureBuildPercentage = GetPercentageAsString(stats.FailureBuildCount, stats.BuildCount);
                stats.SuccessfullBuildPercentage = GetPercentageAsString(stats.SuccessfullBuildCount, stats.BuildCount);

                models.Add(stats);
            });

            return PartialView("UserIndividualStatistics", models);
        }

        private decimal GetPercentageAsString(int total, int share)
        {
            return share == 0 ? 0.0M : Math.Round( Decimal.Divide(total, share) * 100, 2);
        }

        public ActionResult BuildConfigurations()
        {
            return View();
        }

        public ActionResult GetBuildConfigurationStatistics()
        {
            var models = new List<BuildConfigurationStatistics>();

            var totalBuilds = repository.GetNoOfBuilds();
            var totalErrorBuilds = repository.GetNoOfErrorBuilds();
            var totalFailureBuilds = repository.GetNoOfFailingBuilds();
            var totalSuccessfullBuilds = repository.GetNoOfSuccessfullBuilds();

            configurations.ForEach(config =>
            {
                var stats = new BuildConfigurationStatistics
                {
                    ProjectId = config.ProjectId,
                    Project = config.ProjectName,
                    Name = config.Name,
                    BuildCount = repository.GetNoOfBuildsByBuildConfig(config),
                    SuccessfullBuildCount = repository.GetNoOfSuccessfullBuildsByBuildConfig(config),
                    ErrorBuildCount = repository.GetNoOfErrorBuildsByBuildConfig(config),
                    FailureBuildCount = repository.GetNoOfFailingBuildsByBuildConfig(config),
                };

                stats.BuildPercentage = GetPercentageAsString(stats.BuildCount, totalBuilds);
                stats.ErrorBuildPercentage = GetPercentageAsString(stats.ErrorBuildCount, totalErrorBuilds);
                stats.FailureBuildPercentage = GetPercentageAsString(stats.FailureBuildCount, totalFailureBuilds);
                stats.SuccessfullBuildPercentage = GetPercentageAsString(stats.SuccessfullBuildCount, totalSuccessfullBuilds);

                models.Add(stats);
            });

            return PartialView("BuildConfigurationStatistics", models);
        }

        public ActionResult GetBuildConfigurationIndividualStatistics()
        {
            var models = new List<BuildConfigurationStatistics>();

            configurations.ForEach(config =>
            {
                var stats = new BuildConfigurationStatistics
                {
                    ProjectId = config.ProjectId,
                    Project = config.ProjectName,
                    Name = config.Name,
                    BuildCount = repository.GetNoOfBuildsByBuildConfig(config),
                    SuccessfullBuildCount = repository.GetNoOfSuccessfullBuildsByBuildConfig(config),
                    ErrorBuildCount = repository.GetNoOfErrorBuildsByBuildConfig(config),
                    FailureBuildCount = repository.GetNoOfFailingBuildsByBuildConfig(config),
                };
                stats.UnknownBuildCount = stats.BuildCount - stats.ErrorBuildCount - stats.FailureBuildCount - stats.SuccessfullBuildCount;
                stats.UnknownBuildPercentage = GetPercentageAsString(stats.UnknownBuildCount, stats.BuildCount);

                stats.BuildPercentage = GetPercentageAsString(stats.BuildCount, stats.BuildCount);
                stats.ErrorBuildPercentage = GetPercentageAsString(stats.ErrorBuildCount, stats.BuildCount);
                stats.FailureBuildPercentage = GetPercentageAsString(stats.FailureBuildCount, stats.BuildCount);
                stats.SuccessfullBuildPercentage = GetPercentageAsString(stats.SuccessfullBuildCount, stats.BuildCount);

                models.Add(stats);
            });

            return PartialView("BuildConfigurationIndividualStatistics", models);
        }

        public ActionResult Projects()
        {
            return View();
        }

        public ActionResult GetProjectStatistics()
        {
            var models = new List<ProjectStatistics>();

            var totalBuilds = repository.GetNoOfBuilds();
            var totalErrorBuilds = repository.GetNoOfErrorBuilds();
            var totalFailureBuilds = repository.GetNoOfFailingBuilds();
            var totalSuccessfullBuilds = repository.GetNoOfSuccessfullBuilds();

            var projects = configurations.GroupBy(conf => new {conf.ProjectId, conf.ProjectName}).ToList();
            
            projects.ForEach(group => {
                                var stats = new ProjectStatistics
                                {
                                    Name = group.Key.ProjectName,
                                    ConfigurationCount = group.Count(),

                                    BuildCount = group.Sum(config => repository.GetNoOfBuildsByBuildConfig(config)),
                                    ErrorBuildCount = group.Sum(config => repository.GetNoOfErrorBuildsByBuildConfig(config)),
                                    FailureBuildCount = group.Sum(config => repository.GetNoOfFailingBuildsByBuildConfig(config)),
                                    SuccessfullBuildCount = group.Sum(config => repository.GetNoOfSuccessfullBuildsByBuildConfig(config))
                                };

                                stats.BuildPercentage = GetPercentageAsString(stats.BuildCount, totalBuilds);
                                stats.ErrorBuildPercentage = GetPercentageAsString(stats.ErrorBuildCount, totalErrorBuilds);
                                stats.FailureBuildPercentage = GetPercentageAsString(stats.FailureBuildCount, totalFailureBuilds);
                                stats.SuccessfullBuildPercentage = GetPercentageAsString(stats.SuccessfullBuildCount, totalSuccessfullBuilds);      
                
                                models.Add(stats);
            });

            return PartialView("ProjectStatistics", models);
        }

        public ActionResult GetProjectIndividualStatistics()
        {
            var models = new List<ProjectStatistics>();

            var projects = configurations.GroupBy(conf => new { conf.ProjectId, conf.ProjectName }).ToList();

            projects.ForEach(group =>
            {
                var stats = new ProjectStatistics
                {
                    Name = group.Key.ProjectName,
                    ConfigurationCount = group.Count(),

                    BuildCount = group.Sum(config => repository.GetNoOfBuildsByBuildConfig(config)),
                    ErrorBuildCount = group.Sum(config => repository.GetNoOfErrorBuildsByBuildConfig(config)),
                    FailureBuildCount = group.Sum(config => repository.GetNoOfFailingBuildsByBuildConfig(config)),
                    SuccessfullBuildCount = group.Sum(config => repository.GetNoOfSuccessfullBuildsByBuildConfig(config))
                };
                stats.UnknownBuildCount = stats.BuildCount - stats.ErrorBuildCount - stats.FailureBuildCount - stats.SuccessfullBuildCount;
                stats.UnknownBuildPercentage = GetPercentageAsString(stats.UnknownBuildCount, stats.BuildCount);

                stats.BuildPercentage = GetPercentageAsString(stats.BuildCount, stats.BuildCount);
                stats.ErrorBuildPercentage = GetPercentageAsString(stats.ErrorBuildCount, stats.BuildCount);
                stats.FailureBuildPercentage = GetPercentageAsString(stats.FailureBuildCount, stats.BuildCount);
                stats.SuccessfullBuildPercentage = GetPercentageAsString(stats.SuccessfullBuildCount, stats.BuildCount);

                models.Add(stats);
            });

            return PartialView("ProjectIndividualStatistics", models);
        }
    }
}
